<?php


namespace app\api\model;


use app\common\model\BaseModel;
use common;
use app\common\library\himongo;
use hiredis;
use ApiOper;
use think\Db;
use think\db\Query;
use think\facade\Log;

class ParkModel extends BaseModel
{
    protected $name = 'park';
    protected $pk = 'id';
    function PARK_ID($city_id)
    {
        $key = 'PARK_ID|' . $city_id;

        $id = hiredis::db()->incr($key);
        if ($id == 1) {
            $where = [
                'city_id' => $city_id,
                'id' => ['<','a']
            ];
            $st = Db::name($this->name)->where($where)->max('id');


            if ($st === NULL) {
                $id = $city_id . "0001";
            } else {
                $id = strval(intval($st) + 1);
            }
            hiredis::db()->set($key, $id);
        }
        return strval($id);
    }

    static function calc_grade($city_id, $coord, $radius)
    {

        $idle_time = (new BikeIdleTimeMap())->point_order_rate($city_id, $coord, $radius);
        $grade = 1;
        $h = intval($idle_time / 3600);
        if ($h <= 1) {
            $grade = 4;
        } else if ($h <= 2) {
            $grade = 3;
        } else if ($h <= 4) {
            $grade = 2;
        }
        return $grade;
    }
    function add($info) {
        $paramlist = [
            'city_id' => 'string',
            'name' => 'string',
            'remark' => 'string',
            'coordinate' => 'array',
            'radius' => 'int',
            'capacity' => 'int',
            'state' => 'int',
            'creator_id' => 'string',
            'creator_name' => 'string',
            'type' => 'string',
            'bike_count' => 'int',
            'grade' => 'int',
            'imgs' => 'array',
            'polygon_type' => 'int',
            'coordinates' => 'array',
            'visitable' => 'array',
            'markers' => 'array',
            'coordinates_mask' => 'array',
            'tmp_id' => 'string',
        ];


        $data = common::type_conver($info, $paramlist);

        if (!$data) {
            $this->throw_myexception(X_ERROR, "service area info error!");
        }

        $data['id'] = $this->PARK_ID($data['city_id']);
        $data['create_time'] = date('Y-m-d H:i:s');
        $data['bike_count'] = 0;
        $data['grade'] = $this->calc_grade($data['city_id'], $data['coordinate'], $data['radius']);
        $data['tmp_id'] = $data['id'];

        ApiOper::instance()->append_creater_info($data);

        self::create($data);

        $this->save_to_mongo($info['city_id'], $data['id']);
        return $data;
    }

    function get_list($city_id, $condition, $pos, $limit)
    {
        $selectlist = [
            'id' => 'string',
            'name' => 'string',
            'remark' => 'string',
            'type' => 'string',
            'coordinate' => 'array',
            'radius' => 'int',
            'capacity' => 'int',
            'state' => 'int',
            'creator_id' => 'string',
            'create_time' => 'string',
            'creator_name' => 'string',
            'updater_id' => 'string',
            'update_time' => 'string',
            'updater_name' => 'string',
            'grade' => 'int',
            'imgs' => 'array',
            'bike_count' => 'int',
            'polygon_type' => 'int',
            'coordinates' => 'array',
            'visitable' => 'array',
            'coordinates_mask' => 'array',
            'tmp_id' => 'string',
        ];

        $sfs = common::array_keys($selectlist);
        $beans = [
            'city_id'=>$city_id,
            'is_deleted'=> 0
        ];

        if (isset($condition['state']) && $condition['state'] != -1) {
            $beans['state'] = $condition['state'];
        }

        if (isset($condition['type'])) {
            $beans['type'] = $condition['type'];
        }

        if (isset($condition['start_time'])) {
            $beans['create_time'] = ['>=',$condition['start_time']];
        }
        if (isset($condition['end_time'])) {
            $beans['create_time'] = ['<=',$condition['end_time']];
        }


        if (!empty($condition['sk'])) {
            if (ctype_alnum($condition['sk'])) {
                $beans['id'] = $condition['sk'];
            } else if (common::is_name($condition['sk'])) {
                $beans['name'] = $condition['sk'];
            } else {
                return [];
            }
        }

        $query = new Query();
        $st = "";
        $tmp_arr = [];
        if (isset($condition['visitable'])) {
            if ($condition['visitable'] & PARK_VISITABLE_FLAG_USER) {
                $st = $st . " and visitable&? > 0";
                $tmp_arr[] = PARK_VISITABLE_FLAG_USER;
            }
            if ($condition['visitable'] & PARK_VISITABLE_FLAG_OPER) {
                $st = $st . " and visitable&? > 0";
                $tmp_arr[] = PARK_VISITABLE_FLAG_OPER;
            }

            $query->where($st,$tmp_arr);
        }
        $rows = $this->where($beans)->where($query)->field($sfs)->limit($pos,$limit)->select();
        return $rows->toArray();
    }

    function count($city_id, $condition)
    {

        $beans = [
            'city_id' => $city_id,
        ];

        if (isset($condition['state'])) {
            $beans['state'] = $condition['state'];
        }

        if (isset($condition['type'])) {
            $beans['type'] = $condition['type'];
        }

        if (isset($condition['start_time'])) {
            $beans['create_time'] = ['>=',$condition['start_time']];
        }
        if (isset($condition['end_time'])) {
            $beans['create_time'] = ['<=',$condition['end_time']];
        }
        if (!empty($condition['sk'])) {
            $beans['name'] = $condition['sk'];
        }


        return Db::name($this->name)->where($beans)->count('id');
    }

    function info($city_id, $id) {
        $selectlist = [
            'city_id' => 'string',
            'id' => 'string',
            'name' => 'string',
            'remark' => 'string',
            'type' => 'string',
            'coordinate' => 'array',
            'capacity' => 'int',
            'state' => 'int',
            'creator_id' => 'string',
            'create_time' => 'string',
            'creator_name' => 'string',
            'updater_id' => 'string',
            'update_time' => 'string',
            'updater_name' => 'string',
            'radius' => 'int',
            'bike_count' => 'int',
            'imgs' => 'array',
            'grade' => 'int',
            'is_deleted' => 'int',
            'polygon_type' => 'int',
            'coordinates' => 'array',
            'visitable' => 'array',
            'markers' => 'array',
            'coordinates_mask' => 'array',
            'tmp_id' => 'string',
        ];

        $sfs = common::array_keys($selectlist);
        $beans = [
            'city_id'=>$city_id,
            'id'=>$id
        ];


        return  $this->where($beans)->field($sfs)->find();
    }

    function update_pa($city_id, $id, $info)
    {
        $paramlist = [
            'name' => 'string',
            'remark' => 'string',
            'coordinate' => 'array',
            'state' => 'int',
            'type' => 'string',
            'capacity' => 'int',
            'grade' => 'int',
            'radius' => 'int',
            'address' => 'string',
            'polygon_type' => 'int',
            'coordinates' => 'array',
            'visitable' => 'array',
            'markers' => 'array',
            'coordinates_mask' => 'array',
        ];

        $data = common::type_conver($info, $paramlist);
        $where = [
            'city_id' => $city_id,
            'id' => $id,
        ];


        ApiOper::instance()->append_updater_info($data);
        // hilog::debug("###########", $data);

        self::create($data, $where);
        $this->sync_to_mongo($data, $where);

        return $data;
    }

    function delete_pa($city_id, $id)
    {
        $data = [
            'is_deleted' => 1,
            'update_time' => date('Y-m-d H:i:s'),
        ];

        $where = [
            'city_id' => $city_id,
            'id' => $id,
        ];

        ApiOper::instance()->append_updater_info($data);
        self::update($data, $where);

        $this->mongo_del($city_id, $id);
    }

    function mongo_del($city_id,$id)
    {
        $where = [
            'eftype' => EB_TYPE_PARK,
            'city_id' => $city_id,
            'id' => $id,
        ];

        himongo::db()->delete($where);
    }

    function incr_bike_count($city_id, $id, $total, $icrement)
    {
        if ($id == null || $city_id == null)
            return;
        if (empty($id) || empty($city_id))
            return;

        $beans = [
            'city_id'=>$city_id,
            'id'=>$id,
        ];


        Db::name($this->name)->where($beans)->setInc('bike',$icrement);

        $data = [
            'bike_count' => $total,
        ];
        $where = [
            'city_id' => $city_id,
            'id' => $id,
            'eftype' => EB_TYPE_PARK,
        ];

        $this->sync_to_mongo($data, $where);
    }

    var $mongo_field = [
        'city_id' => 'string',
        'id' => 'string',
        'name' => 'string',
        'remark' => 'string',
        'type' => 'string',
        'coordinate' => 'array',
        'capacity' => 'int',
        'state' => 'int',
        'creator_id' => 'string',
        'create_time' => 'string',
        'creator_name' => 'string',
        'updater_id' => 'string',
        'update_time' => 'string',
        'updater_name' => 'string',
        'radius' => 'int',
        'bike_count' => 'int',
        'grade' => 'int',
        'imgs' => 'array',
        'is_deleted' => 'int',
        'polygon_type' => 'int',
        'coordinates' => 'array',
        'tmp_id' => 'string',
        'visitable' => 'int',
        'coordinates_mask' => 'array',
    ];

    function save_to_mongo($city_id, $id) {
        $where = [
            'eftype' => EB_TYPE_PARK,
            'city_id' => $city_id,
            'id' => $id,
        ];

        himongo::db()->delete($where);

        $info = (new ParkModel())->info($city_id, $id);
        if ($info['state'] == 0 && $info['is_deleted'] == 0 && $info['tmp_id'] == $id) {
            $info = common::type_conver($info, $this->mongo_field);
            $info['eftype'] = EB_TYPE_PARK;
            if ($info['polygon_type'] == PARK_POLYGON_TYPE_CIRCLE) {
                $info['coordinates'] = common::circle_to_polygon($info['coordinate'], $info['radius']);
            }

            if (isset($info['coordinates'])) {
                $info['polygon'] = [
                    'type' => 'Polygon',
                    'coordinates' => [$info['coordinates']],
                ];
            }

            if (isset($info['coordinate'])) {
                $info['point'] = [
                    'type' => 'Point',
                    'coordinates' => $info['coordinate'],
                ];
            }
            himongo::db()->insert($info);
        }
    }

    function sync_to_mongo($data, $where)
    {
        $where['eftype'] = EB_TYPE_PARK;
        $info = common::type_conver($data, $this->mongo_field);
        if (empty($info))
            return;

        if (isset($info['coordinates'])) {
            $info['polygon'] = [
                'type' => 'Polygon',
                'coordinates' => [$info['coordinates']],
            ];
        }

        if (isset($info['coordinate'])) {
            $info['point'] = [
                'type' => 'Point',
                'coordinates' => $info['coordinate'],
            ];
        }

        $where['eftype'] = EB_TYPE_PARK;
        $where['tmp_id'] = $where['id'];
        himongo::db()->update($where, $info);
    }

    function is_in($city_id, $coordinate, $visitable = -1) {
        return $this->is_in_polygon($city_id, $coordinate, $visitable);
    }

    function is_in_circle($city_id, $coordinate) {
        $condition = [
            'eftype' => EB_TYPE_PARK,
            'city_id' => $city_id,
        ];

        $projection = [
            'city_id' => 1,
            'id' => 1,
            'name' => 1,
            'coordinate' => 1,
            'capacity' => 1,
            'state' => 1,
            'radius' => 1,
            'bike_count' => 1,
            'grade' => 1,
            'imgs' => 1,
        ];
        $result = himongo::db()->near($coordinate[0], $coordinate[1], 200, 100, $condition, $projection);

        foreach ($result as $item) {
            $distance = common::distance($coordinate, $item['coordinate']);
            if ($item['radius'] > $distance) {
                return $item;
            }
        }
        return false;
    }

    function is_in_polygon($city_id, $coordinate, $visitable = -1) {
        // $visitable = -1;
        $condition = [
            'eftype' => EB_TYPE_PARK,
            'city_id' => $city_id,
        ];

        if ($visitable > 0) {
            if (($visitable & PARK_VISITABLE_FLAG_USER) && ($visitable & PARK_VISITABLE_FLAG_OPER)) {
                $condition['visitable'] = PARK_VISITABLE_FLAG_USER & PARK_VISITABLE_FLAG_OPER;
            } else if ($visitable & PARK_VISITABLE_FLAG_USER) {
                $condition['visitable'] = [
                    '$in' => [
                        PARK_VISITABLE_FLAG_USER,
                        PARK_VISITABLE_FLAG_USER | PARK_VISITABLE_FLAG_OPER
                    ]
                ];
            } else if ($visitable & PARK_VISITABLE_FLAG_OPER) {
                $condition['visitable'] = [
                    '$in' => [
                        PARK_VISITABLE_FLAG_OPER,
                        PARK_VISITABLE_FLAG_USER | PARK_VISITABLE_FLAG_OPER
                    ]
                ];
            }
        }

        $projection = [
            'city_id' => 1,
            'id' => 1,
            'name' => 1,
            'coordinate' => 1,
            'capacity' => 1,
            'state' => 1,
            'radius' => 1,
            'bike_count' => 1,
            'grade' => 1,
            'imgs' => 1,
        ];
        // $result = himongo::db()->near($coordinate[0], $coordinate[1], 200, 100, $condition, $projection);


        $result = himongo::db()->runconmand_intersects($coordinate, $condition, 5);
        if (empty($result)) {
            return false;
        }

        return $result[0];

        foreach ($result as $item) {
            $distance = common::distance($coordinate, $item['coordinate']);
            if ($item['radius'] > $distance) {
                return $item;
            }
        }
        return false;
    }

    function query_list_near($city_id, $coordinate, $distance = PARK_NEARLY_DISTANCE_OPER, $visitable = -1, $polygon_type = -1) {
        $polygon_type = -1;
        $condition = [
            'eftype' => EB_TYPE_PARK,
            'state' => 0,
            'city_id' => $city_id,
        ];
//        $cfg = CityConfigCache::getcfg($city_id);
//        if ($cfg->park_type == USER_PARK_TYPE_FREE) {
//            $visitable = -1;
//        }

        if ($visitable > 0) {
            if (($visitable & PARK_VISITABLE_FLAG_USER) && ($visitable & PARK_VISITABLE_FLAG_OPER)) {
                $condition['visitable'] = PARK_VISITABLE_FLAG_USER & PARK_VISITABLE_FLAG_OPER;
            } else if ($visitable & PARK_VISITABLE_FLAG_USER) {
                $condition['visitable'] = [
                    '$in' => [
                        PARK_VISITABLE_FLAG_USER,
                        PARK_VISITABLE_FLAG_USER | PARK_VISITABLE_FLAG_OPER
                    ]
                ];
            } else if ($visitable & PARK_VISITABLE_FLAG_OPER) {
                $condition['visitable'] = [
                    '$in' => [
                        PARK_VISITABLE_FLAG_OPER,
                        PARK_VISITABLE_FLAG_USER | PARK_VISITABLE_FLAG_OPER
                    ]
                ];
            }
        }

        if ($polygon_type > 0) {
            $condition['polygon_type'] = $polygon_type;
        }

        $projection = [
            'city_id' => 1,
            'id' => 1,
            'name' => 1,
            'coordinate' => 1,
            'capacity' => 1,
            'state' => 1,
            'radius' => 1,
            'bike_count' => 1,
            'grade' => 1,
            'imgs' => 1,
            'coordinates' => 1,
            'polygon_type' => 1,
            'coordinates_mask' => 1,
        ];
        $result = himongo::db()->near($coordinate[0], $coordinate[1], $distance, 1000, $condition, $projection);
        $l = [];
        foreach ($result as $item) {
            $l[] = common::type_conver($item, $this->mongo_field);
        }
        return $l;
    }

    function update_grade($city_id) {
        $st = "SELECT start_park_id, AVG(if(bike_idle_time<28800,bike_idle_time,28800)) as idletime from tb_user_ride_order where city_id =  ? and create_time > ? and create_time <= ?  and start_park_id is not null group by start_park_id";
        echo $st;
        $beans = [
            $city_id,
            date('Y-m-d 00:00:00', strtotime('-7 days')),
            date('Y-m-d H:i:s'),
        ];
        var_dump($beans);
        $result = hisql::db()->query($st, $beans);
        $rows = $result->fetchAll(Phalcon\Db::FETCH_ASSOC);

        var_dump($rows);
        foreach ($rows as $row) {
            $grade = 4;
            $idletime = intval($row['idletime']);
            $h = floor($idletime / 3600);
            if ($h == 0) {
                $grade = 4;
            } else if ($h <= 1) {
                $grade = 1;
            } else if ($h <= 3) {
                $grade = 2;
            } else if ($h <= 5) {
                $grade = 3;
            }

            $data = [
                'grade' => $grade,
            ];
            $this->update($city_id, $row['start_park_id'], $data);
        }
    }

    function update_grade_bak($city_id) {
        $rows = $this->where(['city_id'=>$city_id,'state'=>0])->field(['id','coordinate','radius','grade'])->select()->toArray();
        foreach ($rows as $row) {
            $coord = json_decode($row['coordinate'], true);
            if ($coord) {
                $grade = self::calc_grade($city_id, $coord, intval($row['radius']));

                Log::debug("park_update_grate {$city_id} {$row['id']} grade origin = {$row['grade']}, new={$grade} ");
                if ($grade != intval($row['grade'])) {
                    $data = [
                        'grade' => $grade,
                    ];
                    $this->update_pa($city_id, $row['id'], $data);
                    Log::debug("update park grade {$city_id} {$row['id']}: {$grade}");
                }
            }
        }
    }

}